package org.exteen.parser;

import org.apache.commons.jexl2.JexlEngine;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

public class ScriptHandler implements ContentHandler {

    private static final char ESC = '\\';
    private static final String ELPREFIX = "${";
    private static final String ELSUFFIX = "}";
    
    private Node current;
    private Node root;
    private JexlEngine jexl;
    private StringBuilder currentText = new StringBuilder();
    
    public ScriptHandler(JexlEngine jexl) {
        this.current = null;
        this.jexl = jexl;
    }

    @Override
    public void characters(char[] chars, int s, int n) throws SAXException {
        currentText.append(chars, s, n);
    }

    private void appendCurrentText() throws SAXException {
        if (currentText.length()==0) {
            return;
        }
        parseCharacters(currentText, current);
        currentText.setLength(0);
    }

    private void parseCharacters(CharSequence text, ExprTokensBuilder current) {
        boolean esc = false;
        int n = text.length();
        for (int i = 0; i<n; i++) {
            char c = text.charAt(i);
            if (!esc) {
                if (c==ESC) {
                    esc = true;
                    continue;
                }
                if (c==ELPREFIX.charAt(0)) {
                    String candidate = text.subSequence(i, n).toString();
                    if (candidate.startsWith(ELPREFIX)) {
                        candidate = candidate.substring(ELPREFIX.length());
                        int six = candidate.indexOf(ELSUFFIX);
                        if (six > 0) {
                            String el = candidate.substring(0, six);
                            current.appendExpression(jexl.createExpression(el));
                            i = i + ELPREFIX.length() + six;
                            continue;
                        }
                    }
                }
            }
            current.append(c);
            esc = false;
        }
        current.close();
    }

    private final static Attr[] NOATTRS = new Attr[0];

    @Override
    public void startElement(String namespace, String tag, String fullTag,
            Attributes attributes) throws SAXException {

        appendCurrentText();

        Attr[] attrs = NOATTRS;
        int n = attributes.getLength();
        if (n>0) {
            attrs = new Attr[n];
            for (int i = 0; i<n; i++) {
                String value = attributes.getValue(i);
                String ns = attributes.getURI(i);
                if (ns.length()==0) {
                    ns = null;
                }
                attrs[i] = new Attr(ns, attributes.getLocalName(i));
                parseCharacters(value, attrs[i]);
            }
        }
        current = new Node(current, namespace, tag, fullTag, attrs);
        if (root==null) {
            root = current;
        }
    }

    @Override
    public void endElement(String namespace, String tag, String fullTag) throws SAXException {
        appendCurrentText();
        current = current.endElement();
    }

    @Override
    public void endDocument() throws SAXException {
        // quiet
    }

    @Override
    public void endPrefixMapping(String s) throws SAXException {
        // quiet
    }

    @Override
    public void ignorableWhitespace(char[] ac, int i, int j)
            throws SAXException {
        // quiet
    }

    @Override
    public void processingInstruction(String s, String s1) throws SAXException {
        // quiet
    }

    @Override
    public void setDocumentLocator(Locator locator) {
        // quiet
    }

    @Override
    public void skippedEntity(String s) throws SAXException {
        // quiet
    }

    @Override
    public void startDocument() throws SAXException {
        // quiet
    }

    @Override
    public void startPrefixMapping(String s, String s1) throws SAXException {
        // quiet
    }

    public Node getRoot() {
        return root;
    }
    
}
